package com.example.yimai.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.yimai.dto.PageResponseDTO;
import com.example.yimai.dto.UserLoginResponseDTO;
import com.example.yimai.entity.User;
import com.example.yimai.mapper.UserMapper;
import com.example.yimai.repository.UserRepository;
import com.example.yimai.service.CaptchaService;
import com.example.yimai.service.UserService;
import com.example.yimai.utils.ESUtil;
import com.example.yimai.utils.JWTUtil;
import com.example.yimai.utils.ParamUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.io.Serializable;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {


    @Autowired
    private UserRepository userRepository;

    @Autowired
    private ElasticsearchOperations elasticsearchOperations;

    @Autowired
    private JWTUtil jwtUtil;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private CaptchaService captchaService;

    @Override
    public UserLoginResponseDTO login(String loginName, String password) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getLoginName, loginName);
        User user = getOne(queryWrapper);
        //检查用户是否存在
        if (user == null || user.getDeleted() == 1){
            throw new RuntimeException("用户不存在");
        }
        //验证密码（数据库中存储的是MD5加密后的密码，所以需要对输入的密码进行MD5加密后比较）
        String encryptedPassword = encryptPassword(password);
        if(!user.getPassword().equals(encryptedPassword)){
            throw new RuntimeException("密码错误");
        }
        log.info(user.getLoginName()+"登录成功");
        UserLoginResponseDTO responseDTO = new UserLoginResponseDTO();
        responseDTO.setData(user);
        //生成token
        String token = jwtUtil.generateToken(user.getId(),user.getLoginName(),user.getType());
        //将token保存到redis中
        redisTemplate.opsForValue().set(loginName, token, jwtUtil.getExpiration(), TimeUnit.MILLISECONDS);

        responseDTO.setToken(token);
        return responseDTO;
    }

    @Override
    public String logout(String token) {
        // 检查token
        if (token == null || token.isEmpty()){
            throw new RuntimeException("请先登录");
        }
        // 获取实际token
        token = token.substring(7);
        // 删除redis中的token
        try{
            String key = jwtUtil.getLoginName(token);
            redisTemplate.opsForValue().getAndDelete(key);
            log.info(key+"退出登录");
            return "success";
        }catch (Exception e){
            throw new RuntimeException("登出失败"+e.getMessage());
        }
    }

    @Override
    public User register(Map<String, Object> registerParams) {
        // 获取用户名和验证码
        String loginName = (String) registerParams.get("loginName");
        String verifyCode = (String) registerParams.get("verifyCode");
        
        // 验证验证码
        if (loginName == null || verifyCode == null) {
            throw new RuntimeException("用户名和验证码不能为空");
        }
        
        // 验证验证码
        boolean isValid = verifyCaptcha(loginName, verifyCode);
        if (!isValid) {
            throw new RuntimeException("验证码错误或已过期");
        }
        
        User user = parseUser(registerParams);
        try {
            save(user);
            userRepository.save(user);
            return user;
        }catch (Exception e){
            String errorMsg = e.getMessage();
            if (errorMsg.contains("Duplicate entry")){
                errorMsg = ":用户已存在";
            }
            throw new RuntimeException("注册失败"+errorMsg);
        }
    }

    @Override
    public PageResponseDTO<User> queryUser(String keyword, int pageNum, int pageSize) {
        try {
            //构建查询参数
            BoolQueryBuilder params;
            if(keyword == null || keyword.isEmpty())
                params = QueryBuilders.boolQuery();
            else {
                params = QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("userName", keyword));
                try{
                    LocalDate date = LocalDate.parse(keyword);
                    params.should(QueryBuilders.matchQuery("createTime", date));
                }catch (Exception e){
                    //忽略
                }
            }

            //构建查询
            NativeSearchQuery query = ESUtil.buildQuery(pageNum, pageSize, params);
            //获取查询结果
            SearchHits<User> searchHits = elasticsearchOperations.search(query, User.class);
            //将结果解析为User数组
            List<User> users = searchHits.getSearchHits().stream().map(hit ->{
                User user = hit.getContent();
                return user;
            }).toList();
            //构建返回对象
            PageResponseDTO<User> results = new PageResponseDTO<>();
            results.setData(users);
            results.setTotal((int)searchHits.getTotalHits());
            results.setPageNum(pageNum + 1);
            results.setPageSize(pageSize);
            return results;
        }catch (Exception e){
            throw new RuntimeException("查询用户数据失败"+e.getMessage());
        }
    }

    @Override
    public String addUser(Map<String, Object> params) {
        User user = parseUser(params);
        try {
            save(user);
            userRepository.save(user);
            return "success";
        }catch (Exception e){
            String errorMsg = e.getMessage();
            if (errorMsg.contains("Duplicate entry")){
                errorMsg = ":用户已存在";
            }
            return "添加失败" + errorMsg;
        }
    }

    @Override
    public String deleteUser(Integer id) {
        try {
            removeById(id);
            return "success";
        }catch (Exception e){
            return "删除失败";
        }
    }

    @Override
    public String updateUser(Map<String, Object> params) {
        try {
            // 检查用户ID是否存在
            if (params.get("id") == null || params.get("id").toString().trim().isEmpty()) {
                return "更新失败: 用户ID不能为空";
            }
            
            User user = parseUser(params);
            UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id",user.getId());
            update(user,updateWrapper);
            return "success";
        }catch (Exception e){
            String errorMsg = e.getMessage();
            if (errorMsg.contains("Duplicate entry")){
                errorMsg = ":用户已存在";
            }
            return "更新失败" + errorMsg;
        }
    }

    @Override
    public boolean verifyCaptcha(String key, String captcha) {
        return captchaService.verifyCaptcha(key, captcha);
    }

    @Override
    public boolean checkPassword(Integer userId, String oldPassword) {
        // 检查用户是否存在
        User user = getById(userId);
        if (user == null || user.getDeleted() == 1) {
            return false;
        }
        // 验证密码是否正确（数据库中存储的是MD5加密后的密码，所以需要对输入的密码进行MD5加密后比较）
        String encryptedPassword = encryptPassword(oldPassword);
        return user.getPassword().equals(encryptedPassword);
    }

    /**
     * 对密码进行MD5加密
     * @param password 原始密码
     * @return 加密后的密码
     */
    private String encryptPassword(String password) {
        return DigestUtils.md5DigestAsHex(password.getBytes());
    }

    private User parseUser(Map<String, Object> params) {
        User user = new User();
        // User实体类的id是String类型，但ParamUtil返回Integer，需要转换
        Integer id = ParamUtil.parseParamsInt(params, "id");
        if (id != null) {
            user.setId(String.valueOf(id));
        }
        user.setLoginName((String) params.get("loginName"));
        user.setUserName((String) params.get("userName"));
        // 如果密码参数存在，对其进行MD5加密
        String password = (String) params.get("password");
        if (password != null && !password.isEmpty()) {
            user.setPassword(encryptPassword(password));
        } else {
            user.setPassword(password);
        }
        user.setSex(ParamUtil.parseParamsInt(params,"sex"));
        user.setIdentityCode((String) params.get("identityCode"));
        user.setEmail((String) params.get("email"));
        user.setMobile((String) params.get("mobile"));
        user.setType(1); // 默认普通用户
        return user;
    }

    public boolean isUserLegal(Map<String,Object> params){
        if (params.get("id") == null)return false;
        else return getById((Serializable) params.get("id")).getDeleted() != 1;
    }

}
